#ifndef __ST7735_H__
#define __ST7735_H__

#include "ugui.h"
#include "main.h"


/* 仅用于演示。最小值为32KB，128KB及以上将启用所有测试 */
#define DEMO_FLASH_KB 32

/* 选择要使用的硬件SPI端口 */
#define LCD_HANDLE            hspi1

/* 引脚连接。使用与CubeMX中相同的名称 */
#define LCD_DC                TFT_DC_Pin  /* 数据和命令选择引脚 */
#define LCD_RST               TFT_RES_Pin /* 如果显示器没有RST引脚则禁用 */
#define LCD_CS                TFT_CS_Pin  /* 如果显示器没有CS引脚则禁用 */
#define LCD_BL                TFT_BLK_Pin /* 如果需要背光控制则启用 */

#define USE_DMA                       /* 尽可能使用DMA进行传输 */
//#define LCD_LOCAL_FB                /* 使用本地帧缓冲区。需要大量RAM，但可消除闪烁和重绘故障 */

//#define USE_ST7735                    /* LCD选择 */
#define USE_ST7789

#define LCD_ROTATION 2                /* XY旋转/镜像。有效值：0...3 */

#ifdef USE_ST7735                     /* ST7735 LCD尺寸 */
  #define LCD_160X128
//#define LCD_128X128
//#define LCD_160X80
#elif defined USE_ST7789              /* ST7789 LCD尺寸 */
//#define LCD_135X240
//#define LCD_240X240
//#define LCD_240X280
	#define LCD_240X320
#endif




#ifdef USE_ST7735
  #ifdef LCD_160X128
    #define LCD_X_SHIFT 0
    #define LCD_Y_SHIFT 0
    #if (LCD_ROTATION == 0) || (LCD_ROTATION == 2)
      #define LCD_WIDTH  128
      #define LCD_HEIGHT 160
    #elif (LCD_ROTATION == 1) || (LCD_ROTATION == 3)
      #define LCD_WIDTH  160
      #define LCD_HEIGHT 128
    #endif
  #elif defined LCD_128X128
    #define LCD_X_SHIFT 0
    #define LCD_Y_SHIFT 0
    #define LCD_WIDTH  128
    #define LCD_HEIGHT 128
  #elif defined LCD_160X80
    #define LCD_X_SHIFT 0
    #define LCD_Y_SHIFT 0
    #if (LCD_ROTATION == 0) || (LCD_ROTATION == 2)
      #define LCD_WIDTH  80
      #define LCD_HEIGHT 160
    #elif (LCD_ROTATION == 1) || (LCD_ROTATION == 3)
      #define LCD_WIDTH  160
      #define LCD_HEIGHT 80
    #endif
  #endif

  #if LCD_ROTATION == 0
    #ifdef LCD_160X80
      #define LCD_ROTATION_CMD (CMD_MADCTL_MX | CMD_MADCTL_MY | CMD_MADCTL_BGR)
    #else
      #define LCD_ROTATION_CMD (CMD_MADCTL_MX | CMD_MADCTL_MY | CMD_MADCTL_RGB)
    #endif
  #elif LCD_ROTATION == 1
    #ifdef LCD_160X80
      #define LCD_ROTATION_CMD (CMD_MADCTL_MY | CMD_MADCTL_MV | CMD_MADCTL_BGR)
    #else
      #define LCD_ROTATION_CMD (CMD_MADCTL_MY | CMD_MADCTL_MV | CMD_MADCTL_RGB)
    #endif
  #elif LCD_ROTATION == 2
    #ifdef LCD_160X80
      #define LCD_ROTATION_CMD (CMD_MADCTL_BGR)
    #else
      #define LCD_ROTATION_CMD (CMD_MADCTL_RGB)
    #endif
  #elif LCD_ROTATION == 3
    #ifdef LCD_160X80
      #define LCD_ROTATION_CMD (CMD_MADCTL_MX | CMD_MADCTL_MV | CMD_MADCTL_BGR)
    #else
      #define LCD_ROTATION_CMD (CMD_MADCTL_MX | CMD_MADCTL_MV | CMD_MADCTL_RGB)
    #endif
  #endif
	
#elif defined USE_ST7789
  #ifdef LCD_135X240
    #if (LCD_ROTATION == 0) || (LCD_ROTATION == 2)
      #define LCD_WIDTH  135
      #define LCD_HEIGHT 240
    #elif (LCD_ROTATION == 1) || (LCD_ROTATION == 3)
      #define LCD_WIDTH  240
      #define LCD_HEIGHT 135
    #endif
  #elif defined LCD_240X240
    #define LCD_WIDTH  240
    #define LCD_HEIGHT 240
    #define LCD_X_SHIFT 0
    #define LCD_Y_SHIFT 0
  #elif defined LCD_240X280
    #if (LCD_ROTATION == 0) || (LCD_ROTATION == 2)
      #define LCD_WIDTH  240
      #define LCD_HEIGHT 280
      #define LCD_X_SHIFT 0
      #define LCD_Y_SHIFT 0
    #elif (LCD_ROTATION == 1) || (LCD_ROTATION == 3)
      #define LCD_WIDTH  280
      #define LCD_HEIGHT 240
    #endif
	#elif defined LCD_240X320
	#if (LCD_ROTATION == 0) || (LCD_ROTATION == 2)
		#define LCD_WIDTH  240
		#define LCD_HEIGHT 320
		#define LCD_X_SHIFT 0
		#define LCD_Y_SHIFT 0
	#elif (LCD_ROTATION == 1) || (LCD_ROTATION == 3)
		#define LCD_WIDTH  320
		#define LCD_HEIGHT 240
	#endif
  #endif

  #if LCD_ROTATION == 0
    #define LCD_ROTATION_CMD (CMD_MADCTL_MX | CMD_MADCTL_MY | CMD_MADCTL_RGB)
    #ifdef LCD_135X240
      #define LCD_X_SHIFT 53
      #define LCD_Y_SHIFT 40
    #elif defined LCD_240X280
    #endif
  #elif LCD_ROTATION == 1
    #define LCD_ROTATION_CMD (CMD_MADCTL_MY | CMD_MADCTL_MV | CMD_MADCTL_RGB)
    #ifdef LCD_135X240
      #define LCD_X_SHIFT 40
      #define LCD_Y_SHIFT 52
    #elif defined LCD_240X280
    #endif
  #elif LCD_ROTATION == 2
    #define LCD_ROTATION_CMD (CMD_MADCTL_RGB)
    #ifdef LCD_135X240
      #define LCD_X_SHIFT 52
      #define LCD_Y_SHIFT 40
    #elif defined LCD_240X280
      #define LCD_X_SHIFT 20
      #define LCD_Y_SHIFT 0
    #endif
  #elif LCD_ROTATION == 3
    #define LCD_ROTATION_CMD (CMD_MADCTL_MX | CMD_MADCTL_MV | CMD_MADCTL_RGB)
    #ifdef LCD_135X240
      #define LCD_X_SHIFT 40
      #define LCD_Y_SHIFT 53
    #elif defined LCD_240X280
      #define LCD_X_SHIFT 20
      #define LCD_Y_SHIFT 0
    #endif
  #endif
#endif

/* LCD Commands */
typedef enum{
  /* 显示方向控制命令 */
  CMD_MADCTL_MY  = 0x80,  // 行地址顺序控制
  CMD_MADCTL_MX  = 0x40,  // 列地址顺序控制
  CMD_MADCTL_MV  = 0x20,  // 行列交换
  CMD_MADCTL_ML  = 0x10,  // 垂直刷新顺序
  CMD_MADCTL_RGB = 0x00,  // RGB颜色顺序
  CMD_MADCTL_BGR = 0x08,  // BGR颜色顺序
  CMD_MADCTL_MH  = 0x04,  // 水平刷新顺序

  /* 基础命令 */
  CMD_NOP        = 0x00,  // 空操作
  CMD_SWRESET    = 0x01,  // 软件复位
  CMD_RDDID      = 0x04,  // 读显示ID
  CMD_RDDST      = 0x09,  // 读显示状态
  CMD_SLPIN      = 0x10,  // 进入睡眠模式
  CMD_SLPOUT     = 0x11,  // 退出睡眠模式
  CMD_PTLON      = 0x12,  // 部分显示开启
  CMD_NORON      = 0x13,  // 正常显示开启

  /* 显示控制命令 */
  CMD_INVOFF     = 0x20,  // 关闭显示反转
  CMD_INVON      = 0x21,  // 开启显示反转
  CMD_GAMSET     = 0x26,  // 设置伽马曲线
  CMD_DISPOFF    = 0x28,  // 关闭显示
  CMD_DISPON     = 0x29,  // 开启显示
  CMD_CASET      = 0x2A,  // 设置列地址
  CMD_RASET      = 0x2B,  // 设置行地址
  CMD_RAMWR      = 0x2C,  // 写显存
  CMD_RAMRD      = 0x2E,  // 读显存
  CMD_PTLAR      = 0x30,  // 设置部分显示区域
  CMD_MADCTL     = 0x36,  // 设置显示方向
  CMD_IDMOFF     = 0x38,  // 关闭空闲模式
  CMD_IDMON      = 0x39,  // 开启空闲模式
  CMD_COLMOD     = 0x3A,  // 设置像素格式

  /* 电源控制命令 */
  CMD_RAMCTRL    = 0xB0,  // RAM控制
  CMD_FRMCTR1    = 0xB1,  // 帧率控制1
  CMD_RGBCTRL    = 0xB1,  // RGB控制
  CMD_FRMCTR2    = 0xB2,  // 帧率控制2
  CMD_PORCTRL    = 0xB2,  // 门控制
  CMD_FRMCTR3    = 0xB3,  // 帧率控制3
  CMD_FRCTRL1    = 0xB3,  // 帧率控制1
  CMD_INVCTR     = 0xB4,  // 显示反转控制
  CMD_PARCTRL    = 0xB5,  // 部分显示控制
  CMD_DISSET5    = 0xB6,  // 显示设置5
  CMD_GCTRL      = 0xB7,  // 门控制
  CMD_VCOMS      = 0xBB,  // VCOM设置
  CMD_PWCTR1     = 0xC0,  // 电源控制1
  CMD_LCMCTRL    = 0xC0,  // LCM控制
  CMD_PWCTR2     = 0xC1,  // 电源控制2
  CMD_IDSET      = 0xC1,  // ID设置
  CMD_PWCTR3     = 0xC2,  // 电源控制3
  CMD_VDVVRHEN   = 0xC2,  // VDV/VCOM电压使能
  CMD_PWCTR4     = 0xC3,  // 电源控制4
  CMD_VRHS       = 0xC3,  // VCOM电压设置
  CMD_PWCTR5     = 0xC4,  // 电源控制5
  CMD_VDVS       = 0xC4,  // VDV电压设置
  CMD_VMCTR1     = 0xC5,  // VCOM电压控制1
  CMD_VCMOFSET   = 0xC5,  // VCOM偏移设置
  CMD_FRCTRL2    = 0xC6,  // 帧率控制2
  CMD_PWCTRL1    = 0xD0,  // 电源控制1

  /* ID读取命令 */
  CMD_RDID1      = 0xDA,  // 读ID1
  CMD_RDID2      = 0xDB,  // 读ID2
  CMD_RDID3      = 0xDC,  // 读ID3
  CMD_RDID4      = 0xDD,  // 读ID4

  /* 其他控制命令 */
  CMD_PWCTR6     = 0xFC,  // 电源控制6
  CMD_GMCTRP1    = 0xE0,  // 正极伽马校正
  CMD_GMCTRN1    = 0xE1,  // 负极伽马校正
  CMD_COLOR_MODE_16bit = 0x55,  // 16位色模式
  CMD_COLOR_MODE_18bit = 0x66,  // 18位色模式
}lcd_cmds;

#define color565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
#define ABS(x) ((x) > 0 ? (x) : -(x))

#define LCD_CON(a,b)  a##b
#define LCD_PIN(pin, out)   ( LCD_CON(pin,_GPIO_Port->BSRR) = (out ? LCD_CON(pin,_Pin) : LCD_CON(pin,_Pin)<<16 ))

extern SPI_HandleTypeDef    LCD_HANDLE;

void LCD_init(void);
void LCD_SetRotation(uint8_t m);
void LCD_DrawPixel(int16_t x, int16_t y, uint16_t color);
void LCD_DrawPixelFB(int16_t x, int16_t y, uint16_t color);
int8_t LCD_Fill(uint16_t xSta, uint16_t ySta, uint16_t xEnd, uint16_t yEnd, uint16_t color);

/* Graphical functions. */
int8_t LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
void LCD_DrawImage(uint16_t x, uint16_t y, UG_BMP* bmp);
void LCD_InvertColors(uint8_t invert);

/* Text functions. */
void LCD_PutChar(uint16_t x, uint16_t y, char ch, UG_FONT* font, uint16_t color, uint16_t bgcolor);
void LCD_PutStr(uint16_t x, uint16_t y,  char *str, UG_FONT* font, uint16_t color, uint16_t bgcolor);

/* Extended Graphical functions. */
/* Command functions */
void LCD_TearEffect(uint8_t tear);

/* Simple test function. */
void LCD_Test(void);

#endif // __ST7735_H__
